﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AccessControl.Video.Rtp
{
	/// <summary>
	/// Represents H264 RTP packet
	/// </summary>
	/// <remarks></remarks>
	class H264RtpPacket : RtpPacket
	{
		#region Fields

		byte[] _payload;

		#endregion

		#region Public Constructors

		/// <summary>
		/// Initializes a new instance of the <see cref="RtpPacket"/> class.
		/// </summary>
		/// <param name="bytes">The bytes.</param>
		/// <remarks></remarks>
		public H264RtpPacket(byte[] bytes) : this(bytes, null, null)
		{			
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="H264RtpPacket"/> class.
		/// </summary>
		/// <param name="bytes">The bytes.</param>
		/// <param name="sps">The SPS.</param>
		/// <param name="pps">The PPS.</param>
		/// <remarks></remarks>
		public H264RtpPacket(byte[] bytes, byte[] sps, byte[] pps) : base(bytes)
		{
			int idx = 0;
			byte[] finalPayload;
			int nFinalPayloadSize = 0;
			byte[] start_seq = new byte[] { 0x00, 0x00, 0x00, 0x01 };

			/* Get the base payload */
			byte[] basePayload = Payload;
			/* Get the nal */
			byte nal = basePayload[0];
			/* Gte the type */
			byte type = (byte)(nal & 0x1F);
			if (type == 28)
			{
				byte startbit = (byte)(basePayload[1] >> 7);
				if (startbit != 0)
				{
					byte reconstructed_nal = (byte)(basePayload[0] & 0xE0);
					reconstructed_nal |= (byte)(basePayload[1] & 0x1F);

					if (sps != null)
						nFinalPayloadSize += sps.Length + start_seq.Length;
					if (pps != null)
						nFinalPayloadSize += pps.Length + start_seq.Length;

					nFinalPayloadSize += (start_seq.Length) + 1 + (basePayload.Length - 2);

					finalPayload = new byte[nFinalPayloadSize];

					/* SPS */
					if (sps != null)
					{
						/* Start sequence first */
						Array.Copy(start_seq, 0, finalPayload, idx, start_seq.Length);
						idx += start_seq.Length;
						Array.Copy(sps, 0, finalPayload, idx, sps.Length);
						idx += sps.Length;
					}

					/* PPS */
					if (pps != null)
					{
						Array.Copy(start_seq, 0, finalPayload, idx, start_seq.Length);
						idx += start_seq.Length;
						Array.Copy(pps, 0, finalPayload, idx, pps.Length);
						idx += pps.Length;
					}

					/* And the rest of the payload */
					Array.Copy(start_seq, 0, finalPayload, idx, start_seq.Length);
					idx += start_seq.Length;
					/* Nal */
					finalPayload[idx] = reconstructed_nal;
					idx++;
					Array.Copy(basePayload, 2, finalPayload, idx, basePayload.Length - 2);
				}
				else
				{
					/* Just copy without the first 2 bytes */
					finalPayload = new byte[basePayload.Length - 2];
					Array.Copy(basePayload, 2, finalPayload, 0, basePayload.Length - 2);
				}
			}
			else if (type == 6 || type == 7 || type == 8)
			{
				nFinalPayloadSize = basePayload.Length + start_seq.Length;
				finalPayload = new byte[nFinalPayloadSize];
				Array.Copy(start_seq, 0, finalPayload, idx, start_seq.Length);
				idx += start_seq.Length;
				Array.Copy(basePayload, 0, finalPayload, idx, basePayload.Length);
			}
			else
			{
				/* Just copy */
				finalPayload = basePayload;
			}

			Payload = finalPayload;
		}

		#endregion
	}
}
